package cn.iocoder.yudao.module.vos.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import cn.hutool.json.JSONObject;
import cn.iocoder.yudao.module.vos.job.vo.PushItem;

import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.*;

/**
 * TIDE 批量发送模板短信客户端（1.7 接口）
 * /api/batchSendTemplateSms
 * <p>
 * 同时实现 1.1 线索导入接口 /api/batchImportClue
 * - 线索导入入参：List<PushItem>（内部映射为 ClueImportItem）
 * - 加解密、签名规则与模板短信接口一致
 */
public class TideTemplateSmsClient {

    // ========== 写死的配置 ==========
    /**
     * 例如：https://open.tideint.com
     */
    private static final String DEFAULT_BASE_URL = "https://open.tideint.com";
    /**
     * 文档中的 merchantCode
     */
    private static final String DEFAULT_MERCHANT_CODE = "M457868432";
    /**
     * PKCS8 BASE64 私钥
     */
    private static final String DEFAULT_RSA_PRIVATE_KEY_BASE64 =
            "MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAJLNtiNuUeoZuq8GG7Lj3t84ZnIkAEOO1+RUVKpMXkGhjEbY3PHu8taMHcOWCHUPYhjsJsSkOkeV3XeXSNjYzFmV/6DZUHIVS3ZsG5ZIU0SllYBzL2txDaqfLv9J0cFHVcZ3INmj6Z17XztDoUKdKujbxoP5o+yY67LTBq/nNTmhAgMBAAECgYEAhQjCa+1HcjwKvx1r8Hsrt2GnBPy2+IH0B0icyQ8Xw6YgNvvDjcMacW7ccif+VgawwSEQKNcisUiQQBXqwAgHdiwym1GHc5ly/6WDaD/D28q/NhjDA3QQU3HGMr5Z73GOu1PQK7TaGqvVdSgvwcFY/oqsxsGm5Nj+H+5lzZy2ddkCQQDiUGLW6kIzSZ1ogm6oODJYdQ8j8OoGnEEYvaIEhJCn4+EX/x5p6552lgvrYS83BREyXyRZO3b8MJLKK5LKbCGDAkEApg9eRLv6aWFAWf5BCPZW4x5r8om4/81tEWW3FOrrlpTvu083vCTYJ9RhG0dej4IPwFJBLOoOdD4d7/xLu4PDCwJBAMQJP+TMXPXSQZCi0znSHAI1vBy09fMt7NGCilKBhlB3+6ZuriiwGb69MKv+rghp0kCg23qUIPhJFw4a+ndvfQMCQQCZ/nB2HzhWFxidG/plfEQQ9Ho4fd0wYuk9E+1XGY+FofI66niOIkDNltbCfEnFnWBMAjtsklT7GUub7ISyjLsHAkEAkV1IzVmKBIG1UV7kwSZ89RM2LtPz/uKqnrV3W/3neNxU2XHw1XaK4yobHbMbul8z+bGzGsTVZCVdOsgGc/QC0A==";
    /**
     * AES 256 key（32 字节）
     */
    private static final String DEFAULT_AES_KEY = "7GNDQDsjLujNXKP6BWTKDthUHFpJXl16";

    /**
     * 线索导入默认呼叫策略 ID（可按实际改成你们申请到的 callStrategyId）
     */
    private static final String DEFAULT_CALL_STRATEGY_ID = "CALL_STRATEGY_DEFAULT";

    /**
     * 例如：https://open.tideint.com
     */
    private final String baseUrl;
    /**
     * 文档中的 merchantCode
     */
    private final String merchantCode;

    /**
     * RSA 私钥（JDK 对象），用于签名
     */
    private final PrivateKey privateKey;
    /**
     * AES256，用于 bizData 加密/解密
     */
    private final SymmetricCrypto aes;

    public TideTemplateSmsClient(String baseUrl,
                                 String merchantCode,
                                 String rsaPrivateKeyBase64,
                                 String aesKeyPlainText) {
        this.baseUrl = trimTrailingSlash(baseUrl);
        this.merchantCode = merchantCode;

        // 1）解析 RSA PKCS8 私钥（BASE64）
        try {
            byte[] keyBytes = java.util.Base64.getDecoder().decode(rsaPrivateKeyBase64);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            this.privateKey = keyFactory.generatePrivate(keySpec);
        } catch (Exception e) {
            throw new IllegalArgumentException("解析 RSA 私钥失败，请确认是 PKCS8 BASE64 格式", e);
        }

        // 2）AES256：key 长度需 32 字节
        byte[] aesKeyBytes = aesKeyPlainText.getBytes(StandardCharsets.UTF_8);
        if (aesKeyBytes.length != 32) {
            throw new IllegalArgumentException("AES key 长度必须为 32 字节（256-bit），当前为 " + aesKeyBytes.length);
        }
        this.aes = new SymmetricCrypto(SymmetricAlgorithm.AES, aesKeyBytes);
    }

    private String trimTrailingSlash(String url) {
        if (url == null) {
            return "";
        }
        if (url.endsWith("/")) {
            return url.substring(0, url.length() - 1);
        }
        return url;
    }

    // =========================================================
    // 1.7 批量发送模板短信 /api/batchSendTemplateSms
    // =========================================================

    /**
     * 1.7 批量发送模板短信
     */
    public JSONObject batchSendTemplateSms(List<TemplateSmsItem> smsList) {
        if (smsList == null || smsList.isEmpty()) {
            throw new IllegalArgumentException("smsList 不能为空");
        }

        // 1）serialNumber / timestamp
        String serialNumber = generateSerialNumber();
        String timestamp = String.valueOf(System.currentTimeMillis());

        // 2）bizData 原始 JSON 数组
        String bizDataJson = JSONUtil.toJsonStr(smsList);

        // 3）AES256 加密 + Base64
        byte[] encryptedBytes = aes.encrypt(bizDataJson.getBytes(StandardCharsets.UTF_8));
        String bizDataBase64 = java.util.Base64.getEncoder().encodeToString(encryptedBytes);

        // 4）签名原文
        String signContent = StrUtil.format(
                "merchantCode={}&serialNumber={}&timestamp={}&bizData={}",
                merchantCode, serialNumber, timestamp, bizDataBase64
        );

        // 5）RSA 签名（默认 SHA256withRSA，如对方要求 MD5withRSA 就把算法改掉）
        String sign = rsaSign(signContent);

        // 6）请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("merchantCode", merchantCode);
        headers.put("serialNumber", serialNumber);
        headers.put("timestamp", timestamp);
        headers.put("sign", sign);
        headers.put("Content-Type", "application/json;charset=UTF-8");

        // 7）请求体
        JSONObject body = new JSONObject();
        body.put("bizData", bizDataBase64);

        String url = baseUrl + "/api/batchSendTemplateSms";

        // 8）HTTP 调用
        HttpResponse httpResponse = HttpRequest.post(url)
                .addHeaders(headers)
                .body(body.toString())
                .timeout(15_000)
                .execute();

        String respBody = httpResponse.body();
        System.out.println("HTTP Status: " + httpResponse.getStatus());
        System.out.println("Response Body: " + respBody);

        return JSONUtil.parseObj(respBody);
    }

    // =========================================================
    // 1.1 线索导入接口 /api/batchImportClue
    // =========================================================

    /**
     * 1.1 线索导入接口：使用通用 DTO（ClueImportItem）调用 TIDE 的 /api/batchImportClue 接口。
     * <p>
     * bizData 为线索集合 JSON，经 AES256 加密后再做 Base64，签名内容为：
     * merchantCode=xxx&serialNumber=xxx&timestamp=xxx&bizData=xxx
     */
    public JSONObject batchImportClue(List<ClueImportItem> clueList) {
        if (clueList == null || clueList.isEmpty()) {
            throw new IllegalArgumentException("clueList 不能为空");
        }

        // 1）serialNumber / timestamp
        String serialNumber = generateSerialNumber();
        String timestamp = String.valueOf(System.currentTimeMillis());

        // 2）bizData 原始 JSON 数组（线索集合）
        String bizDataJson = JSONUtil.toJsonStr(clueList);

        // 3）AES256 加密 + Base64
        byte[] encryptedBytes = aes.encrypt(bizDataJson.getBytes(StandardCharsets.UTF_8));
        String bizDataBase64 = java.util.Base64.getEncoder().encodeToString(encryptedBytes);

        // 4）签名原文（与文档一致）
        String signContent = StrUtil.format(
                "merchantCode={}&serialNumber={}&timestamp={}&bizData={}",
                merchantCode, serialNumber, timestamp, bizDataBase64
        );

        // 5）RSA 签名
        String sign = rsaSign(signContent);

        // 6）请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("merchantCode", merchantCode);
        headers.put("serialNumber", serialNumber);
        headers.put("timestamp", timestamp);
        headers.put("sign", sign);
        headers.put("Content-Type", "application/json;charset=UTF-8");

        // 7）请求体
        JSONObject body = new JSONObject();
        body.put("bizData", bizDataBase64);

        String url = baseUrl + "/api/batchImportClue";

        // 8）HTTP 调用
        HttpResponse httpResponse = HttpRequest.post(url)
                .addHeaders(headers)
                .body(body.toString())
                .timeout(15_000)
                .execute();

        String respBody = httpResponse.body();
        System.out.println("[TIDE] /api/batchImportClue HTTP Status: " + httpResponse.getStatus());
        System.out.println("[TIDE] /api/batchImportClue Response Body: " + respBody);

        return JSONUtil.parseObj(respBody);
    }

    /**
     * 使用写死配置，根据 PushItem 列表调用「线索导入接口」/api/batchImportClue。
     * <p>
     * - 入参依然是 List<PushItem>：只强依赖 phoneE164。
     * - bizData(JSON) 形如：
     * [{"taskName":"KMJ_IMPORT_20251114190456","callStrategyId":"1045","phone":"09286539406"}]
     *
     * @param pushItemList   线索来源（只强依赖 phoneE164）
     * @param taskName       TIDE 任务名称（唯一标识一个任务）。为空则自动生成 "KMJ_IMPORT_yyyyMMddHHmmss"。
     * @param callStrategyId 呼叫策略 ID，TIDE 平台侧配置的策略 ID。不传则用 DEFAULT_CALL_STRATEGY_ID。
     */
    public static void importClueForPushItems(List<PushItem> pushItemList,
                                              String taskName,
                                              String callStrategyId) {
        if (pushItemList == null || pushItemList.isEmpty()) {
            System.out.println("[TIDE] importClueForPushItems pushItemList 为空，跳过线索导入");
            return;
        }

        // 任务名称：为空则自动生成
        if (StrUtil.isBlank(taskName)) {
            taskName = "KMJ_IMPORT_" + pushItemList.get(0).getTenantId().toString() + "_" + DateUtil.format(DateUtil.date(), "yyyyMMdd");
        }

        // 呼叫策略 ID：为空则使用默认
        if (StrUtil.isBlank(callStrategyId)) {
            callStrategyId = DEFAULT_CALL_STRATEGY_ID;
        }

        // 使用写死的配置创建客户端
        TideTemplateSmsClient client = new TideTemplateSmsClient(
                DEFAULT_BASE_URL,
                DEFAULT_MERCHANT_CODE,
                DEFAULT_RSA_PRIVATE_KEY_BASE64,
                DEFAULT_AES_KEY
        );

        // 构造线索集合（这里只输出 taskName / callStrategyId / phone）
        List<ClueImportItem> clueList = new ArrayList<>();
        for (PushItem item : pushItemList) {
            if (item == null) {
                continue;
            }
            String phone = item.getPhoneE164();
            if (StrUtil.isBlank(phone)) {
                continue;
            }

            ClueImportItem clue = new ClueImportItem();
            clue.setTaskName(taskName);
            clue.setCallStrategyId(callStrategyId);
            clue.setPhone(phone);

            clueList.add(clue);
        }

        if (clueList.isEmpty()) {
            System.out.println("[TIDE] importClueForPushItems 有效号码为空，跳过线索导入");
            return;
        }

        // 打印 bizData(JSON) 预览
        try {
            String bizDataPreview = JSONUtil.toJsonStr(clueList);
            System.out.println("[TIDE] importClueForPushItems 请求参数：");
            System.out.println("  taskName      = " + taskName);
            System.out.println("  callStrategyId= " + callStrategyId);
            System.out.println("  bizData(JSON) = " + bizDataPreview);
        } catch (Exception e) {
            System.out.println("[TIDE] importClueForPushItems 打印请求参数失败：" + e.getMessage());
        }

        try {
            System.out.println("[TIDE] 即将导入线索，条数=" + clueList.size()
                    + ", taskName=" + taskName + ", callStrategyId=" + callStrategyId);
            JSONObject resp = client.batchImportClue(clueList);
            System.out.println("[TIDE] 线索导入完成，原始响应=" + resp);

            String rtCode = resp.getStr("rtCode");
            String msg = resp.getStr("msg");

            System.out.println("[TIDE] rtCode = " + rtCode);
            System.out.println("[TIDE] msg    = " + msg);
        } catch (Exception e) {
            System.out.println("[TIDE] 线索导入接口调用异常：" + e.getMessage());
            e.printStackTrace();
        }
    }

    // =========================================================
    // 通用工具：签名 / 解密 / 序列号
    // =========================================================

    /**
     * JDK 实现的 RSA 签名
     */
    private String rsaSign(String content) {
        try {
            // 和对接方确认用什么算法；常见 "SHA256withRSA" 或 "MD5withRSA"
            Signature signature = Signature.getInstance("SHA256withRSA");
            signature.initSign(privateKey);
            signature.update(content.getBytes(CharsetUtil.CHARSET_UTF_8));
            byte[] signBytes = signature.sign();
            return java.util.Base64.getEncoder().encodeToString(signBytes);
        } catch (Exception e) {
            throw new RuntimeException("RSA 签名失败", e);
        }
    }

    /**
     * 解密响应中的 data 字段（Base64 + AES256）
     */
    public String decryptData(String base64Ciphertext) {
        if (base64Ciphertext == null || base64Ciphertext.isEmpty()) {
            return null;
        }
        byte[] encrypted = java.util.Base64.getDecoder().decode(base64Ciphertext);
        byte[] plainBytes = aes.decrypt(encrypted);
        return new String(plainBytes, StandardCharsets.UTF_8);
    }

    /**
     * 生成请求流水号
     */
    private String generateSerialNumber() {
        String prefix = DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss");
        String random = IdUtil.fastSimpleUUID().substring(0, 6);
        return prefix + random;
    }

    // ========= DTO：单条模板短信 =========
    public static class TemplateSmsItem {
        private String phone;               // 手机号
        private Long templateId;            // 模板ID
        private Map<String, String> valMap; // 模板变量

        public TemplateSmsItem() {
        }

        public TemplateSmsItem(String phone, Long templateId, Map<String, String> valMap) {
            this.phone = phone;
            this.templateId = templateId;
            this.valMap = valMap;
        }

        public String getPhone() {
            return phone;
        }

        public void setPhone(String phone) {
            this.phone = phone;
        }

        public Long getTemplateId() {
            return templateId;
        }

        public void setTemplateId(Long templateId) {
            this.templateId = templateId;
        }

        public Map<String, String> getValMap() {
            return valMap;
        }

        public void setValMap(Map<String, String> valMap) {
            this.valMap = valMap;
        }
    }

    // ========= DTO：线索导入（1.1 接口） =========

    /**
     * 按当前接入要求，仅包含：
     * - taskName
     * - callStrategyId
     * - phone
     * <p>
     * 生成的 bizData(JSON) 示例：
     * [{"taskName":"KMJ_IMPORT_20251114190456","callStrategyId":"1045","phone":"09286539406"}]
     */
    public static class ClueImportItem {
        private String taskName;
        private String callStrategyId;
        private String phone;

        public ClueImportItem() {
        }

        public String getTaskName() {
            return taskName;
        }

        public void setTaskName(String taskName) {
            this.taskName = taskName;
        }

        public String getCallStrategyId() {
            return callStrategyId;
        }

        public void setCallStrategyId(String callStrategyId) {
            this.callStrategyId = callStrategyId;
        }

        public String getPhone() {
            return phone;
        }

        public void setPhone(String phone) {
            this.phone = phone;
        }
    }

    // ========= 静态方法：直接用 PushItem + templateId 发送模板短信 =========

    /**
     * 使用写死的 TIDE 配置，根据 PushItem 列表发送模板短信。
     * 注意：HTTP 请求中的 bizData 结构仍然是 List<TemplateSmsItem>，
     * 这里只是把 PushItem 映射成 TemplateSmsItem，valMap 传 null。
     *
     * @param pushItemList PushItem 列表（只用 phoneE164 字段）
     * @param templateId   模板 ID
     */
    public static void sendTemplateSmsForPushItems(List<PushItem> pushItemList, Long templateId) {
        if (pushItemList == null || pushItemList.isEmpty()) {
            System.out.println("[TIDE] pushItemList 为空，跳过发送");
            return;
        }
        if (templateId == null) {
            throw new IllegalArgumentException("templateId 不能为空");
        }

        // 使用写死的配置创建客户端
        TideTemplateSmsClient client = new TideTemplateSmsClient(
                DEFAULT_BASE_URL,
                DEFAULT_MERCHANT_CODE,
                DEFAULT_RSA_PRIVATE_KEY_BASE64,
                DEFAULT_AES_KEY
        );

        // 仍然构造 List<TemplateSmsItem>，保持原来的 bizData 结构
        List<TemplateSmsItem> smsList = new ArrayList<>();
        for (PushItem item : pushItemList) {
            if (item == null) {
                continue;
            }
            String phone = item.getPhoneE164();
            if (StrUtil.isBlank(phone)) {
                continue;
            }
            // 和原 main 中示例保持一致：valMap 传 null
            smsList.add(new TemplateSmsItem(phone, templateId, null));
        }

        if (smsList.isEmpty()) {
            System.out.println("[TIDE] 有效号码为空，跳过发送");
            return;
        }

        try {
            System.out.println("[TIDE] 即将发送模板短信，条数=" + smsList.size());
            JSONObject resp = client.batchSendTemplateSms(smsList);
            System.out.println("[TIDE] 调用完成，原始响应=" + resp);

            String rtCode = resp.getStr("rtCode");
            String msg = resp.getStr("msg");
            String dataCipher = resp.getStr("data"); // 加密的 data

            System.out.println("[TIDE] rtCode = " + rtCode);
            System.out.println("[TIDE] msg    = " + msg);
            System.out.println("[TIDE] data (ciphertext) = " + dataCipher);

            if (StrUtil.isNotBlank(dataCipher)) {
                try {
                    String dataPlain = client.decryptData(dataCipher);
                    System.out.println("[TIDE] data (decrypted) = " + dataPlain);
                } catch (Exception e) {
                    System.out.println("[TIDE] 解密 data 失败：" + e.getMessage());
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            System.out.println("[TIDE] 模板短信调用异常：" + e.getMessage());
            e.printStackTrace();
        }
    }

    // ========= main 测试入口 =========
    public static void main(String[] args) {
        // 示例：构造一条 PushItem，调用静态方法发送模板短信
        List<PushItem> list = new ArrayList<>();

        PushItem item = new PushItem();
        item.setTenantId(1001L);
        item.setListDate("2025-11-11");
        item.setListLevel("A");
        item.setPhoneE164("09286539406"); // 只会用到这一项
        item.setPhoneMd5("xxxx-md5");
        item.setPhoneTags("tag1,tag2");
        item.setMarketingTools("sms");

        list.add(item);

        Long templateId = 4238299092645576961L;
//        sendTemplateSmsForPushItems(list, templateId);

        // 示例：调用线索导入（callStrategyId = "1045"）
        importClueForPushItems(list, null, "1045");
    }
}
